AWS IoT Coreポリシーでiot:Publishとiot:Receiveをまとめて許可すると、トピック設計によっては本来必要なアクションまでブロックするかもしれない
IoT デバイスでメッセージを受信できない
おのやんです。
みなさん、AWS IoT Core(以下、IoT Core)にて、デバイス上でメッセージの受信ができない現象に遭遇したことはありませんか?私はあります。
具体的には以下の現象です。
- IoT CoreにはIoT Core ポリシーを設定している
- デバイスからIoT Coreへのメッセージのパブリッシュは可能
- IoT Coreからデバイスへメッセージを送信しても、デバイス側でメッセージを認識しない
こちらの現象について調査する機会がありましたので、これから紹介していきます。
3行まとめ
- パブリッシュ用トピックとサブスクライブ用トピックを分けている場合、IoT Coreポリシーをまとめて許可すると本来必要なアクションまでブロックする可能性がある
iot:Receive
アクションを許可する対象は、サブスクライブ用トピック- 許可するアクションは、ひとつひとつ分けて書こう
IoT Core ポリシーがどうなっていたか
今回のケースでは、IoT Coreで以下のようにポリシーを設定していました。公式ドキュメントにも載っている、デバイスの接続・メッセージのやりとりをIoT Coreに登録しているデバイスのみに限定しているポリシーです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:client/${iot:Connection.Thing.ThingName}",
"Condition": {
"Bool": {
"iot:Connection.Thing.IsAttached": [
"true"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topic/pub/${iot:Connection.Thing.ThingName}"
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topicfilter/sub/${iot:Connection.Thing.ThingName}"
}
]
}
また今回は、IoT Coreトピックの設計として、パブリッシュ用とサブスクライブ用でそれぞれトピックをpub/
始まりとsub/
始まりに分けていました。
原因
では、上記の設定でデバイスのメッセージ受信が許可されない原因はどこにあるのでしょうか?
こちらに結構時間を溶かしてしまったのですが、原因はこの部分です。
topic/
で指定できるiot:Publish
とiot:Receive
を同じResource
で許可しています。
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topic/pub/${iot:Connection.Thing.ThingName}"
},
こちらお気づきの方もいるかと思いますが、この状態ではiot:Publish
もiot:Receive
もパブリッシュ用トピックを許可してしまっています。
本来であれば、iot:Receive
を許可する対象は、パブリッシュ用ではなくサブスクライブ用のトピックです。
「トピックを同じtopic/
で指定できるから、iot:Publish
とiot:Receive
をまとめて許可しよう」と考えたことが原因で、本体sub/
始まりのトピックを指定するべきiot:Receive
アクションにて、pub/
始まりのトピックを指定していました。
そのため、横着せずににポリシーをiot:Publish
とiot:Receive
をしっかり書き分けて、めでたくデバイス上でメッセージを受信できるようになりました。
{
"Version": "2012-10-17",
"Statement": [
{
"Condition": {
"Bool": {
"iot:Connection.Thing.IsAttached": [
"true"
]
}
},
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:client/${iot:Connection.Thing.ThingName}"
},
{
"Effect": "Allow",
"Action": "iot:Publish",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topic/pub/${iot:Connection.Thing.ThingName}"
},
{
"Effect": "Allow",
"Action": "iot:Receive",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topic/sub/${iot:Connection.Thing.ThingName}"
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": "arn:aws:iot:ap-northeast-1:<account_id>:topicfilter/sub/${iot:Connection.Thing.ThingName}"
}
]
}
ポリシーJSONの記述では横着しない
ものすごく細かいミスですが、どのリソースを許可するかという最も基本的な考えを改めて確認する必要があるなと思いました。特にIoT Coreポリシーではデバイスとのやりとりに関しての権限となるので、詳細に記述することが大切です。
余談ですが、公式ドキュメントではiot:Publish
とiot:Receive
はしっかり書き分けされていたので、ちゃんと公式ドキュメントを読みましょうという自戒も込めてみました。では!